package com.example.base_model.other

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import java.net.Socket

/**
 * @Author jiangKunKun
 * @CreateDate 2025/9/17
 * @Description 局域网管理类，用于处理UDP广播和TCP连接。
 * @SpittingGrooves
 */
class IntranetManager {
    /**
     * 用于线程同步的锁对象
     */
    private val lock = Any()

    /**
     * UDP套接字实例
     */
    private var udpSocket: DatagramSocket? = null
    /**
     * TCP套接字实例
     */
    private var tcpSocket: Socket? = null

    /**
     * HTTP客户端实例 (当前代码中未使用，但保留)
     */
    private var httpClient: OkHttpClient? = null

    /**
     * TCP输出流，用于发送数据
     */
    private var tcpOutputStream: OutputStream? = null

    /**
     * TCP输入流，用于接收数据
     */
    private var tcpInputStream: InputStream? = null

    /**
     * TCP连接状态，true表示已连接，false表示未连接
     */
    private var tcpState = false

    /**
     * 服务器IP地址
     */
    private var serverIp: String? = null
    /**
     * 服务器端口号
     */
    private var serverPort: Int = 0

    /**
     * UDP广播任务的Job对象
     */
    private var udpBroadcastJob: Job? = null
    /**
     * TCP心跳任务的Job对象
     */
    private var tcpHeartbeatJob: Job? = null
    /**
     * TCP消息接收任务的Job对象
     */
    private var tcpReceiveJob: Job? = null

    companion object {
        // UDP广播端口号
        const val UDP_BROADCAST_PORT = 8881
        // 心跳发送间隔时间（毫秒）
        const val HEARTBEAT_INTERVAL = 10000L // 10秒
        // 心跳响应超时时间（毫秒）
        const val HEARTBEAT_TIMEOUT = 5000L // 5秒
    }

    /**
     * 解析服务器信息字符串。
     * 假设服务器返回格式为 "IP:PORT"。
     *
     * @param response 服务器返回的字符串。
     * @return [ServerInfo] 对象，如果解析失败则返回 null。
     */
    private fun parseServerInfo(response: String): ServerInfo? {
        try {
            val parts = response.trim().split(":")
            if (parts.size == 2) {
                val ip = parts[0]
                val port = parts[1].toInt()
                return ServerInfo(ip, port)
            }
            return null
        } catch (e: Exception) {
            // 解析异常，返回null
            return null
        }
    }

    /**
     * 启动UDP发现机制，通过广播查找局域网内的服务器。
     * 持续发送UDP广播，直到找到服务器并建立TCP连接。
     */
    private fun startUdpDiscovery() {
        synchronized(lock) {
            // 清理之前的UDP资源，但不关闭TCP连接
            cleanupUdpResources()
            udpBroadcastJob = CoroutineScope(Dispatchers.IO).launch {
                // 当协程活跃且TCP未连接时，持续进行UDP广播
                while (currentCoroutineContext().isActive && !tcpState) {
                    try {
                        // 发送UDP广播
                        sendUdpBroadcast()

                        // 等待接收UDP响应
                        val serverInfo = receiveUdpResponse()
                        if (serverInfo != null) {
                            // 接收到服务器信息，更新服务器IP和端口
                            serverIp = serverInfo.ip
                            serverPort = serverInfo.port
                            tcpState = true // 设置TCP状态为已连接（准备连接）

                            // 启动TCP连接
                            startTcpConnection()
                            break // 成功连接后跳出循环
                        }
                    } catch (e: Exception) {
                        // 广播或接收过程中出现异常，继续下一次广播
                    }

                    // 间隔5秒后继续发送广播
                    delay(5000)
                }
            }
        }
    }

    /**
     * 启动局域网管理服务，开始UDP发现。
     */
    fun start() {
        startUdpDiscovery()
    }

    /**
     * 发送UDP广播包。
     * 创建UDP套接字，设置超时，并向广播地址发送数据。
     */
    private fun sendUdpBroadcast() {
        udpSocket = DatagramSocket()
        udpSocket?.soTimeout = 3000 // 设置3秒超时

        val broadcastData = "udp发送数据测试".toByteArray(Charsets.UTF_8)
        val packet = DatagramPacket(
            broadcastData,
            broadcastData.size,
            InetAddress.getByName("255.255.255.255"), // 广播地址
            UDP_BROADCAST_PORT
        )
        udpSocket?.send(packet)
    }

    /**
     * 接收UDP广播响应。
     * 等待并接收服务器的UDP响应，然后解析服务器信息。
     *
     * @return [ServerInfo] 对象，如果接收或解析失败则返回 null。
     */
    private fun receiveUdpResponse(): ServerInfo? {
        try {
            val buffer = ByteArray(1024)
            val packet = DatagramPacket(buffer, buffer.size)
            udpSocket?.receive(packet)

            // 解析服务器返回的IP和端口信息
            val response = String(packet.data, 0, packet.length, Charsets.UTF_8)
            return parseServerInfo(response)
        } catch (e: Exception) {
            // 接收或解析异常，返回null
            return null
        }
    }

    /**
     * 启动TCP连接到发现的服务器。
     * 建立TCP套接字，获取输入输出流，并启动心跳和消息监听。
     */
    private fun startTcpConnection() {
        synchronized(lock) {
            CoroutineScope(Dispatchers.IO).launch {
                try {
                    // 创建TCP套接字连接到服务器
                    tcpSocket = Socket(serverIp, serverPort)
                    tcpOutputStream = tcpSocket?.getOutputStream()
                    tcpInputStream = tcpSocket?.getInputStream()

                    synchronized(lock) {
                        tcpState = true // 标记TCP连接成功
                    }

                    // 启动TCP消息接收协程
                    startTCPMessageListener()

                    // 启动心跳机制
                    startHeartbeat()

                } catch (e: Exception) {
                    // 连接失败，更新TCP状态
                    synchronized(lock) {
                        tcpState = false
                    }
                    // 关闭TCP连接资源
                    closeTcpConnections()
                    // 重新开始UDP发现，尝试重连
                    startUdpDiscovery()
                }
            }
        }
    }

    /**
     * 启动TCP消息监听协程。
     * 持续读取TCP输入流中的数据，并处理接收到的消息。
     */
    private fun startTCPMessageListener() {
        tcpReceiveJob = CoroutineScope(Dispatchers.IO).launch {
            try {
                // 当协程活跃且TCP连接有效时，持续接收消息
                while (currentCoroutineContext().isActive && tcpState) {
                    val buffer = ByteArray(1024)
                    val bytesRead = tcpInputStream?.read(buffer)
                    if (bytesRead != null && bytesRead > 0) {
                        val message = String(buffer, 0, bytesRead, Charsets.UTF_8)
                        // 处理接收到的TCP消息
                        handleReceivedTCPMessage(message)
                    }
                }
            } catch (e: IOException) {
                // 读取异常，通常表示连接断开，更新TCP状态
                synchronized(lock) {
                    tcpState = false
                }
                // 重新开始UDP发现，尝试重连
                startUdpDiscovery()
            }
        }
    }

    /**
     * 处理接收到的TCP消息。
     * 这是一个占位方法，实际的消息处理逻辑应在此处实现。
     *
     * @param message 接收到的消息字符串。
     */
    private fun handleReceivedTCPMessage(message: String) {
        // 在这里处理接收到的TCP消息，例如更新UI或执行业务逻辑
    }

    /**
     * 启动TCP心跳机制。
     * 定期发送心跳包，并检查心跳响应，如果连续超时则触发重连。
     */
    private fun startHeartbeat() {
        tcpHeartbeatJob = CoroutineScope(Dispatchers.IO).launch {
            var heartbeatTimeoutCount = 0 // 心跳超时计数器
            val maxTimeoutCount = 3 // 最大允许的心跳超时次数

            // 当协程活跃且TCP连接有效时，持续发送心跳
            while (currentCoroutineContext().isActive && tcpState) {
                try {
                    // 发送心跳包
                    sendHeartbeat()

                    // 等待心跳响应（设置超时）
                    if (!waitForHeartbeatResponse(HEARTBEAT_TIMEOUT)) {
                        heartbeatTimeoutCount++ // 超时计数增加
                        if (heartbeatTimeoutCount >= maxTimeoutCount) {
                            // 心跳超时过多，认为连接已断开，重新开始UDP发现
                            tcpState = false
                            startUdpDiscovery()
                            break // 跳出心跳循环
                        }
                    } else {
                        heartbeatTimeoutCount = 0 // 收到响应，重置超时计数
                    }

                    // 间隔一定时间后再次发送心跳
                    delay(HEARTBEAT_INTERVAL)
                } catch (e: Exception) {
                    // 心跳过程中出现异常，认为连接已断开，重新开始UDP发现
                    tcpState = false
                    startUdpDiscovery()
                    break // 跳出心跳循环
                }
            }
        }
    }

    /**
     * 发送心跳包到TCP连接。
     */
    private fun sendHeartbeat() {
        try {
            tcpOutputStream?.write("HEARTBEAT".toByteArray(Charsets.UTF_8))
            tcpOutputStream?.flush()
        } catch (e: IOException) {
            // 发送心跳失败，认为连接已断开，更新TCP状态
            synchronized(lock) {
                tcpState = false
            }
        }
    }

    /**
     * 发送TCP消息。
     *
     * @param message 要发送的消息字符串。
     * @return 发送是否成功。
     */
    fun sendTCPMessage(message: String): Boolean {
        return synchronized(lock) {
            if (tcpState && tcpOutputStream != null) {
                try {
                    tcpOutputStream?.write(message.toByteArray(Charsets.UTF_8))
                    tcpOutputStream?.flush()
                    true // 发送成功
                } catch (e: IOException) {
                    // 发送失败，认为连接已断开
                    tcpState = false
                    // 触发重连机制
                    CoroutineScope(Dispatchers.IO).launch {
                        startUdpDiscovery()
                    }
                    false // 发送失败
                }
            } else {
                false // TCP未连接或输出流不可用
            }
        }
    }

    /**
     * 等待心跳响应。
     * 设置TCP套接字的读取超时时间，尝试读取响应，并判断是否为有效的心跳响应。
     *
     * @param timeout 等待响应的超时时间（毫秒）。
     * @return 如果收到有效的心跳响应则返回 true，否则返回 false。
     */
    private fun waitForHeartbeatResponse(timeout: Long): Boolean {
        return try {
            // 设置输入流的读取超时时间
            tcpSocket?.soTimeout = timeout.toInt()

            val buffer = ByteArray(1024)
            val bytesRead = tcpInputStream?.read(buffer)

            if (bytesRead != null && bytesRead > 0) {
                val response = String(buffer, 0, bytesRead)
                // 检查是否为有效的心跳响应（根据实际协议调整，例如包含 "HEARTBEAT_ACK" 或 "PONG"）
                response.contains("HEARTBEAT_ACK") || response.contains("PONG")
            } else {
                false // 没有读取到数据
            }
        } catch (e: IOException) {
            // 超时或读取异常，表示心跳失败
            false
        } catch (e: Exception) {
            false
        } finally {
            // 重置超时时间为默认值（0表示无限等待）或保持连接
            try {
                tcpSocket?.soTimeout = 0 // 0表示无限等待
            } catch (e: Exception) {
                // 忽略设置超时异常
            }
        }
    }

    /**
     * 清理UDP相关资源（仅在UDP发现阶段调用）。
     * 关闭UDP套接字并取消UDP广播任务。
     */
    private fun cleanupUdpResources() {
        synchronized(lock) {
            try {
                udpSocket?.close() // 关闭UDP套接字
            } catch (e: Exception) {
                // 忽略关闭异常
            }
            udpSocket = null

            // 只取消UDP广播任务
            udpBroadcastJob?.cancel()
            udpBroadcastJob = null
        }
    }

    /**
     * 关闭TCP连接相关资源。
     * 关闭TCP套接字，取消TCP相关任务，并清理输入输出流。
     */
    private fun closeTcpConnections() {
        synchronized(lock) {
            // 关闭TCP连接
            try {
                tcpSocket?.close()
            } catch (e: Exception) {
                // 忽略关闭异常
            }
            tcpSocket = null

            // 取消TCP心跳任务
            tcpHeartbeatJob?.cancel()
            tcpHeartbeatJob = null

            // 取消TCP消息接收任务
            tcpReceiveJob?.cancel()
            tcpReceiveJob = null

            // 清理输入输出流
            tcpOutputStream = null
            tcpInputStream = null

            // 重置TCP状态和服务器信息
            tcpState = false
            serverIp = null
            serverPort = 0
        }
    }

    /**
     * 完全关闭所有资源（在应用退出时调用）。
     * 关闭UDP和TCP套接字，取消所有协程任务，并清理所有相关资源。
     */
    fun shutdown() {
        synchronized(lock) {
            // 关闭UDP资源
            try {
                udpSocket?.close()
            } catch (e: Exception) {
                // 忽略关闭异常
            }
            udpSocket = null

            // 关闭TCP连接
            try {
                tcpSocket?.close()
            } catch (e: Exception) {
                // 忽略关闭异常
            }
            tcpSocket = null

            // 取消所有协程任务
            udpBroadcastJob?.cancel()
            udpBroadcastJob = null

            tcpHeartbeatJob?.cancel()
            tcpHeartbeatJob = null

            tcpReceiveJob?.cancel()
            tcpReceiveJob = null

            // 清理输入输出流
            tcpOutputStream = null
            tcpInputStream = null

            // 清理HTTP客户端 (如果使用)
            httpClient = null

            // 重置所有状态和服务器信息
            tcpState = false
            serverIp = null
            serverPort = 0
        }
    }

}

/**
 * 数据类，表示服务器信息（IP地址和端口号）。
 * @param ip 服务器的IP地址。
 * @param port 服务器的端口号。
 */
data class ServerInfo(
    val ip: String,
    val port: Int
)